package com.galen.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.Producer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * helloWorld 测试案例
 *
 * @author GalenGao
 * @version Id: HelloWorldController.java, v 0.1 2022/5/12 9:29 GalenGao Exp $$
 */
@Controller
@RequiredArgsConstructor
@Slf4j
public class HelloWorldController {

    private final ObjectMapper objectMapper;

    private final Producer producer;

    @GetMapping("/helloWorld")
    public ResponseEntity<String> helloWorld() {
        return ResponseEntity.ok("helloWorld");
    }

    /**
     * spring Security 自定义登陆成功跳转的URL必须为post，否则会报错405的问题()
     *
     * @return ResponseEntity<String>
     */
    @PostMapping("/index")
    public ResponseEntity<String> index() {
        return ResponseEntity.ok("login Success！");
    }

    @RequestMapping("/login.html")
    public String login() {
        return "login";
    }

    /**
     * 从SecurityContextHolder 获取用户信息
     * @return Authentication ，默认SecurityContextHolder 上下文存储在ThreadLocal对象中，解决了线程安全问题
     * 但也带来了子线程无法获取认证对象的问题
     * @throws JsonProcessingException
     */
    @GetMapping("/user")
    public ResponseEntity<String> getUser() throws JsonProcessingException {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Map<String, Object> map = new HashMap<>();
        map.put("authentication", authentication);
        String value = objectMapper.writeValueAsString(map);
        // 开启子线程获取认证用户信息
        new Thread(() -> {
            Authentication authentication1 = SecurityContextHolder.getContext().getAuthentication();
            if (authentication1 == null) {
                System.out.println("获取用户信息失败！");
                return;
            }
            System.out.println("子线程获取当前登陆用户名称：" + authentication1.getName());
        }).start();
        return ResponseEntity.ok(value);
    }

    /**
     * 登陆成功后可以直接从HttpServletRequest获取当前已经认证成功的对象
     * @param httpServletRequest HttpServletRequest
     * @return ResponseEntity
     * @throws JsonProcessingException JsonProcessingException
     */
    @GetMapping("/getUserFromServlet")
    public ResponseEntity<String> getUserFromServlet(HttpServletRequest httpServletRequest) throws JsonProcessingException {
        String user = httpServletRequest.getRemoteUser();
        // 底层还是从SecurityContextHolder中获取，具体参考：SecurityContextHolderAwareRequestWrapper#getUserPrincipal 方法
        Authentication userPrincipal = (Authentication) httpServletRequest.getUserPrincipal();
        Map<String, Object> map = new HashMap<>();
        map.put("authentication", userPrincipal);
        map.put("user", user);
        String value = objectMapper.writeValueAsString(map);
        return ResponseEntity.ok(value);
    }

    /**
     * 生成验证码
     * @param resp resp
     * @param httpSession HttpSession
     * @throws IOException  IOException
     */
    @GetMapping("/verify.jpg")
    public void getVerifyCode(HttpServletResponse resp, HttpSession httpSession) throws IOException {
        resp.setContentType("image/kpeg");
        String text = producer.createText();
        httpSession.setAttribute("kaptcha", text);
        BufferedImage image = producer.createImage(text);
        try (OutputStream outputStream = resp.getOutputStream()) {
            ImageIO.write(image,"jpg",outputStream);
        }
    }

    /**
     * 正常的转账业务操作
     */
    @PostMapping("/withDraw")
    @ResponseBody
    public ResponseEntity<String>  withDraw(){
        return ResponseEntity.ok("成功进行了一次转账操作！");
    }
}
